<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';

import MapboxDraw from '@mapbox/mapbox-gl-draw';
import * as VTable from '@visactor/vtable';
import * as VTable_editors from '@visactor/vtable-editors';
import mapboxgl from 'mapbox-gl';
import * as XLSX from 'xlsx';

import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';

const { ListTable } = VTable;

const mapContainer = ref<HTMLDivElement | null>(null);
const tableContainer = ref<HTMLDivElement | null>(null);
const container = ref<HTMLDivElement | null>(null);
const divider = ref<HTMLDivElement | null>(null);
const fileInput = ref<HTMLInputElement | null>(null);

const tableWidth = ref(70); // 表格初始宽度
let isDragging = false;
const input_editor = new VTable_editors.InputEditor();
VTable.register.editor('input-editor', input_editor);
let map: mapboxgl.Map | null = null;
let draw: MapboxDraw | null = null;
let vtable: any = null;
let tableData: any[] = [];

const renderTable = (data: any[]) => {
  if (!tableContainer.value) return;

  const actualData =
    data.length > 0
      ? data
      : [Object.fromEntries(Array.from({ length: 10 }).fill(['字段', '']))];

  const columns = Object.keys(actualData[0]).map((key) => {
    return {
      field: key,
      title: key,
      width: 120,
      minWidth: 100,
    };
  });

  if (vtable) vtable.release();

  vtable = new ListTable({
    container: tableContainer.value,
    records: actualData,
    columns,
    widthMode: 'standard',
    heightMode: 'autoHeight',
    scroll: {
      horizontal: true,
      vertical: true,
    },
    enableLineBreak: true,
    autoWrapText: true,
    limitMaxAutoWidth: 600,
    editCellTrigger: 'click',
    keyboardOptions: {
      copySelected: true,
      pasteValueToCell: true,
      selectAllOnCtrlA: true,
    },
    editor: input_editor,
  });
};

const handleFileUpload = (event: Event) => {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  if (!file) return;

  const reader = new FileReader();
  reader.addEventListener('load', (e) => {
    const data = e.target?.result;
    if (!data) return;

    const workbook = XLSX.read(data, { type: 'array' });
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];
    const json = XLSX.utils.sheet_to_json(worksheet);
    tableData = json;
    renderTable(tableData);
  });
  // eslint-disable-next-line unicorn/prefer-blob-reading-methods
  reader.readAsArrayBuffer(file);

  if (fileInput.value) fileInput.value.value = '';
};

const updateTableWithCoordinates = (coordinates: [number, number][]) => {
  coordinates.forEach(([lon, lat]) => {
    tableData.push({ longitude: lon, latitude: lat });
  });
  renderTable(tableData);
};

const updateTableWithGeoJSON = (feature: any) => {
  const geojson = JSON.stringify(feature.geometry);
  tableData.push({ geojson });
  renderTable(tableData);
};

const initMap = () => {
  if (!mapContainer.value) return;

  mapboxgl.accessToken =
    'pk.eyJ1IjoibmluamFhIiwiYSI6ImNsYXYzd3JwaDAyMGwzdm44ZmI3M212eHQifQ.h_dGMMOvQXNfmheNd0_j8A';

  map = new mapboxgl.Map({
    container: mapContainer.value,
    style: 'mapbox://styles/mapbox/streets-v11',
    center: [118.916_507, 32.113_575],
    zoom: 10,
  });

  map.on('load', () => {
    map.doubleClickZoom.disable();

    draw = new MapboxDraw({
      displayControlsDefault: false,
      controls: {
        point: true,
        line_string: true,
        polygon: true,
        trash: true,
      },
    });

    map.addControl(draw);

    map.on('dblclick', () => {
      draw?.changeMode('simple_select');
    });

    map.on('draw.create', (e) => {
      const features = e.features;
      if (features.length === 0) return;

      features.forEach((feature) => {
        if (feature.geometry.type === 'Point') {
          updateTableWithCoordinates([feature.geometry.coordinates]);
        } else {
          updateTableWithGeoJSON(feature);
        }
      });
    });

    setTimeout(() => map?.resize(), 500);
  });
};

const onDrag = (event: MouseEvent) => {
  if (!isDragging || !container.value) return;

  const containerRect = container.value.getBoundingClientRect();
  let newWidth =
    ((event.clientX - containerRect.left) / containerRect.width) * 100;
  newWidth = Math.max(20, Math.min(80, newWidth));
  tableWidth.value = newWidth;
};
const stopDragging = () => {
  isDragging = false;
  document.body.style.overflow = 'hidden';
  document.removeEventListener('mousemove', onDrag);
  document.removeEventListener('mouseup', stopDragging);
};
const startDragging = () => {
  isDragging = true;
  document.body.style.overflow = 'hidden'; // 保证拖动中无滚动
  document.addEventListener('mousemove', onDrag);
  document.addEventListener('mouseup', stopDragging);
};

watch(tableWidth, () => {
  setTimeout(() => map?.resize(), 100);
});

onMounted(() => {
  initMap();
  renderTable([]);
});
</script>

<template>
  <div class="flex h-full w-full flex-col overflow-hidden">
    <!-- 上传按钮 -->
    <div class="border-b border-gray-200 bg-gray-100 p-2">
      <label
        class="inline-flex cursor-pointer items-center rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
      >
        <span>上传表格</span>
        <input
          ref="fileInput"
          type="file"
          accept=".xlsx,.xls,.csv"
          class="hidden"
          @change="handleFileUpload"
        />
      </label>
    </div>

    <!-- 表格与地图容器 -->
    <div ref="container" class="relative flex w-full flex-1 overflow-hidden">
      <!-- 表格 -->
      <div
        :style="{ width: `${tableWidth}%` }"
        class="flex h-full flex-col overflow-hidden"
      >
        <div
          ref="tableContainer"
          class="flex-1 overflow-auto"
          style="width: 100%; height: 100%; max-height: 100%"
        ></div>
      </div>

      <!-- 拖拽分隔条 -->
      <div
        ref="divider"
        class="w-2 cursor-ew-resize bg-gray-400 hover:bg-gray-600"
        @mousedown="startDragging"
      ></div>

      <!-- 地图 -->
      <div ref="mapContainer" class="h-full flex-1"></div>
    </div>
  </div>
</template>

<style scoped>
.w-2:hover {
  background-color: #bcbbbb;
}

::v-deep(.vtable-container) {
  overflow: auto !important;
  cursor: text;
  user-select: text;
}
</style>
